/**   
 * @Title: BusDpCodeGenerator.java
 * @Package cn.edu.sjtu.se.dslab.component.design.generate
 * @Description: TODO(用一句话描述该文件做什么)
 * @author Thinker
 * @date 2013-7-27 上午8:55:53
 * @version V1.0
 */ 
package cn.edu.sjtu.se.dslab.component.design.generate;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import cn.edu.sjtu.se.dslab.component.aadl.AADLModel;
import cn.edu.sjtu.se.dslab.component.aadl.AADLParser;
import cn.edu.sjtu.se.dslab.component.data.AvionicsEquipment;
import cn.edu.sjtu.se.dslab.component.data.DomainEntity;
import cn.edu.sjtu.se.dslab.component.data.util.DataComponentUtil;
import cn.edu.sjtu.se.dslab.component.dp.parse.DesignPatternInstanceBean;
import cn.edu.sjtu.se.dslab.component.dp.parse.Property;
import cn.edu.sjtu.se.dslab.component.method.InterfaceMethod;
import cn.edu.sjtu.se.dslab.component.method.MethodComponent;
import cn.edu.sjtu.se.dslab.component.method.util.MethodComponentUtil;
import cn.edu.sjtu.se.dslab.project.BusZone;
import cn.edu.sjtu.se.dslab.project.EntityZone;
import cn.edu.sjtu.se.dslab.project.EntityZoneCategory;
import cn.edu.sjtu.se.dslab.project.Project;
import cn.edu.sjtu.se.dslab.rhapsody.entity.Agent;
import cn.edu.sjtu.se.dslab.rhapsody.entity.BusAgent;
import cn.edu.sjtu.se.dslab.rhapsody.entity.Task;
import cn.edu.sjtu.se.dslab.rhapsody.service.RhapsodyFileService;
import cn.edu.sjtu.se.dslab.service.IAvionicsEquipmentService;
import cn.edu.sjtu.se.dslab.service.IBusZoneService;
import cn.edu.sjtu.se.dslab.service.IDataComponentService;
import cn.edu.sjtu.se.dslab.service.IDomainEntityService;
import cn.edu.sjtu.se.dslab.service.IEntityZoneCategoryService;
import cn.edu.sjtu.se.dslab.service.IEntityZoneService;
import cn.edu.sjtu.se.dslab.service.IInterfaceMethodService;
import cn.edu.sjtu.se.dslab.service.IMethodComponentService;
import cn.edu.sjtu.se.dslab.util.Const;
import cn.edu.sjtu.se.dslab.util.FileUtil;

/** 
 * @ClassName: BusDpCodeGenerator
 * @Description: 生成总线设计模式代码
 * @author longshaohang
 * @date 2013-7-27 上午8:55:53
 * 
 */
@Service("busDpcCodeGenerator")
public class BusDpcCodeGenerator extends DesignPatternCodeGenerator{
	
	private static final Logger logger = Logger.getLogger(BusDpcCodeGenerator.class);	
	
	private static final String EQUIPMENT = "equipment";
	private static final String BUS_TYPE = "bus_type";
	private static final String BUS_ZONE = "bus_zone";
	private static final String READ_BUS_INIT_METHOD = "read_bus_init_method";
	private static final String READ_BUS_PROCESSING_METHOD = "read_bus_processing_method";
	private static final String WRITE_BUS_INIT_METHOD = "write_bus_init_method";
	private static final String WRITE_BUS_PROCESSING_METHOD = "write_bus_processing_method";
	
	//private static final String READ_WRITE_AGENT_C_FILE_NAME = "read_write_agent.c";
	//private static final String READ_WRITE_AGENT_H_FILE_NAME = "read_write_agent.h";
	//private static final String CDSF_INJECTION_BUS_C_FILE_NAME = "CDSF_Injection_Bus.c";
	private static final String SHARED_MEMORY_AREA_FILE_NAME = "shared_memory_area.h";
	//private static final String CDSF_INJECTION_BUS_H_FILE_NAME = "CDSF_Injection_Bus.h";
	private static final String BUS_DATA_ZONE_FILE_NAME = "bus_data_zone.h";
	
	private static final String CDSF_CONFIGS_BUS_FILE_NAME = "CDSF_Configs_Bus.c";
	
	//define template file
	//private static final String READ_WRITE_AGENT_C_TEMPLATE_NAME = "read_write_agent_c.vm";
	//private static final String READ_WRITE_AGENT_H_TEMPLATE_NAME = "read_write_agent_h.vm";
	//private static final String CDSF_INJECTION_BUS_C_TEMPLATE_NAME = "cdsf_injection_bus_c.vm";
	private static final String SHARED_MEMORY_AREA_TEMPLATE_NAME = "shared_memory_area.vm";	
	//private static final String CDSF_INJECTION_BUS_H_TEMPLATE_NAME = "cdsf_injection_bus_h.vm";
	private static final String BUS_DATA_ZONE_TEMPLATE_NAME = "bus_data_zone.vm";
	private static final String CDSF_CONFIGS_BUS_TEMPLATE_NAME = "CDSF_Configs_Bus_c.vm";
	
	
	public static final String APPLICATION_C_FILE_NAME = "Application.c";
	public static final String APPLICATION_C_TEMPLATE_NAME = "Application_c.vm";
	
	@Resource(name="aadlParser")
	private AADLParser aadlParser;
	
	@Resource(name="rhapsodyFileService")
	private RhapsodyFileService rhapsodyFileService;
	
	@Resource(name = "dataComponentService")
	IDataComponentService dataComponentService;

	@Resource(name = "domainEntityService")
	IDomainEntityService domainEntityService;
	
	@Resource(name="avionicsEquipmentService")
	IAvionicsEquipmentService avionicsEquipmentService;

	@Resource(name="dataComponentUtil")
	DataComponentUtil dataComponentUtil;
	

	@Resource(name="methodComponentUtil")
	MethodComponentUtil methodComponentUtil;
	
	@Resource(name="interfaceMethodService")
	IInterfaceMethodService interfaceMethodService;
	
	@Resource(name="methodComponentService")
	IMethodComponentService methodComponentService;
	
	
	@Resource(name="busZoneService")
	IBusZoneService busZoneService;
	
	@Resource(name="entityZoneService")
	IEntityZoneService entityZoneService;
	
	@Resource(name="entityZoneCategoryService")
	IEntityZoneCategoryService entityZoneCategoryService;
	
	public BusDpcCodeGenerator(){
		super();
	}

	/** (非 Javadoc) 
	 * Title: generateCode
	 * Description:
	 * @param dpiBean
	 * @return
	 * @throws IOException
	 * @see cn.edu.sjtu.se.dslab.component.design.generate.DesignPatternCodeGenerator#generateCode(cn.edu.sjtu.se.dslab.component.design.parse.DesignPatternInstanceBean)
	 */
	@Override
	public void generateCode(String targetDirPath, Project project, DesignPatternInstanceBean ...dpiBean)
			throws IOException {
		String absoluteTargetDirPath = FileUtil.getRootPath() + targetDirPath;
		logger.info(absoluteTargetDirPath);
		
		Map<String, String> methodComponentFiles = new HashMap<String, String>();
		
		Set<Long> dataEntityIdSet = new HashSet<Long>(); 
		
		Set<String> dependFiles = new HashSet<String>();
		
		List<Map<String, Property>> instances = new ArrayList<Map<String, Property>>();
		for (Map<String, Property> instance : dpiBean[0].getInstances()){
			//get and set all the value 
			instances.add(getInstanceValue(instance,dependFiles, methodComponentFiles));
		}
		inputData("instances", instances);
		
		inputData("dependFileList", dependFiles);
		for (String f : dependFiles){
			logger.info(f);
		}
		for (Entry<String,String> e : methodComponentFiles.entrySet()){
			logger.info(e.getKey() + "====" + e.getValue());
		}
		
		StringBuffer appPath = new StringBuffer(FileUtil.getRootPath());
		appPath.append(targetDirPath).append("App/");
		FileUtil.copyFileList(new HashSet<String>(methodComponentFiles.values()), appPath.toString());
		
		//Get all the Bus
		Set<String> busSet = new HashSet<String>();
		for (Property p : dpiBean[0].getPropertyByName(BUS_TYPE)){
			busSet.add(p.getValue());
		}
		inputData("buses", busSet);
		
		//
		//CDSF_Injection_Bus.c
//		StringBuffer cdsfInjectionBusCFilePath = new StringBuffer(targetDirPath);
//		cdsfInjectionBusCFilePath.append("App/").append(CDSF_INJECTION_BUS_C_FILE_NAME);
//		generateCodeFile(cdsfInjectionBusCFilePath.toString(), CDSF_INJECTION_BUS_C_TEMPLATE_NAME);
		//CDSF_Injection_Bus.h
//		StringBuffer cdsfInjectionBusHFilePath = new StringBuffer(targetDirPath);
//		cdsfInjectionBusHFilePath.append("App/").append(CDSF_INJECTION_BUS_H_FILE_NAME);
//		generateCodeFile(cdsfInjectionBusHFilePath.toString(), CDSF_INJECTION_BUS_H_TEMPLATE_NAME);
		//shared_memory_area.h
		StringBuffer sharedMemoryAreaFilePath = new StringBuffer(targetDirPath);
		sharedMemoryAreaFilePath.append("App/").append(SHARED_MEMORY_AREA_FILE_NAME);
		generateCodeFile(sharedMemoryAreaFilePath.toString(), SHARED_MEMORY_AREA_TEMPLATE_NAME);
	

		//entity_data_area 导入领域实体所依赖的文件
//		List<Property> entityDataAreaPropertys = dpiBean[0]
//				.getPropertyByName(ENTITY_DATA_AREA);
//		List<Long> domainEntityIdList = new ArrayList<Long>();
//		List<String> dependFileList = new ArrayList<String>();
//		for (Property p : entityDataAreaPropertys) {
//			String[] uris = p.getValue().split("/");
//			for (String uri : uris) {
//				DomainEntity domainEntity = domainEntityService
//						.getDomainEntityByUri(uri);
//				domainEntityIdList.add(domainEntity.getId());
//				logger.info("Data Entity :" + domainEntity.getName());
//				if (!dataEntityIdSet.contains(domainEntity.getId())) {
//					dataEntityIdSet.add(domainEntity.getId());
//				}
//			}
//		}
		
		//inputData("entity_data_area", domainEntityList);
		//去掉文件的路径，只剩下文件名
		//data entity 的依赖文件
//		for(String s: dataComponentUtil.getDependences(domainEntityIdList)){
//			String tmp = s.substring(s.lastIndexOf('/')+1,	s.length());
//			dependFileList.add(tmp);
//			FileUtil.copyFile(s, absoluteTargetDirPath + "App/");// 把依赖的文件复制到生成代码的文件夹下
//		}
//		inputData("depend_files", dependFileList);
		//generate data_entity definition file
		//StringBuffer variableFile = new StringBuffer(absoluteTargetDirPath);
		//variableFile.append("App/").append(DATA_ENTITY_FILE_NAME);
		//dataComponentUtil.generateBusData(new ArrayList<Long>(dataEntityIdSet), variableFile.toString());

		
		List<BusZone> busZones = busZoneService.getBusZoneByProject(project.getId());
		logger.info(busZones.size());
		Map<String, List<String> > busZoneMap = new HashMap <String, List<String>>();
		Set<String> entityNames = new HashSet<String>();
		Set<Long> entityIds = new HashSet<Long>();   //所依赖的领域实体的id
		List<String> dependFileList = new ArrayList<String>();	//所有的依赖文件
		
		List<String> bindingList = new ArrayList<String>();		
		for (BusZone busZone : busZones){
			List<String> entityList = new ArrayList<String>();
			
			String entityZoneIds = busZone.getEntityZones();
			if (entityZoneIds == null || entityZoneIds.equals("")) continue;
			String[] ezs = entityZoneIds.split("\\|");
			for (String id : ezs){
				logger.info(id);
				if (id.equals("") || id.equals("|")) continue;
				EntityZone entityZone = entityZoneService.getEntityZoneById(Long.parseLong(id));
				if (entityZone == null) throw new NullPointerException("No such entityZone!");
				DomainEntity entity = domainEntityService.getDomainEntityByUri(entityZone.getEntityUri());
				//DomainEntity entity = domainEntityService.getDomainEntityById(Long.parseLong(id));
				if (entity == null) continue;
				logger.info(entity.getName());
				entityIds.add(entity.getId()); //添加ID
				entityNames.add(entity.getName());
				entityList.add(entity.getName());
				//add the mapping 
				StringBuffer mapping = new StringBuffer();
				mapping.append(busZone.getName().toLowerCase()).append("_bz.");
				mapping.append(entity.getName()).append("_p = ");
				mapping.append(entity.getName().toLowerCase()).append(";");
				bindingList.add(mapping.toString());
			}
			busZoneMap.put(busZone.getName(), entityList);
		}
		inputData("entityNames", entityNames);
		inputData("busZoneMap", busZoneMap);
		inputData("busEntitymapping", bindingList);
		
		//去掉文件的路径，只剩下文件名
		//domain entity 的依赖文件
		for(String s: dataComponentUtil.getDependences(new ArrayList<Long>(entityIds))){
			String tmp = s.substring(s.lastIndexOf('/')+1,	s.length());
			dependFileList.add(tmp);
			FileUtil.copyFile(s, absoluteTargetDirPath + "App/", null);// 把依赖的文件复制到生成代码的文件夹下
		}
		
		
		for(String m: bindingList){
			logger.info(m);
		}
		

		
		//bus data 
		StringBuffer busZoneFilePath = new StringBuffer(targetDirPath);
		busZoneFilePath.append("App/").append(BUS_DATA_ZONE_FILE_NAME);
		generateCodeFile(busZoneFilePath.toString(), BUS_DATA_ZONE_TEMPLATE_NAME);
		
		//App/read_write_agent.h
//		StringBuffer readWriteAgentHeaderFile = new StringBuffer(targetDirPath);
//		readWriteAgentHeaderFile.append("App/").append(READ_WRITE_AGENT_H_FILE_NAME);
//		generateCodeFile(readWriteAgentHeaderFile.toString(), READ_WRITE_AGENT_H_TEMPLATE_NAME);
	
		//App/read_write_agent.c
//		StringBuffer readWriteAgentSourceFile = new StringBuffer(targetDirPath);
//		readWriteAgentSourceFile.append("App/").append(READ_WRITE_AGENT_C_FILE_NAME);
//		generateCodeFile(readWriteAgentSourceFile.toString(), READ_WRITE_AGENT_C_TEMPLATE_NAME);
		
		
		AADLModel model = project.getModel();
		StringBuilder modelFilePath = new StringBuilder(FileUtil.getRootPath());
		modelFilePath.append(Const.GENERATE_PATH).append("/").append(model.getXmlPath());
		File modelFile = new File( modelFilePath.toString());
		//
		List<BusAgent> busAgents = rhapsodyFileService.readDesignPatternBusAgents(project.getId());
		List<Task> tasks = new ArrayList<Task>();
		if (modelFile != null){
			Map<String, Set<Agent>> agents = aadlParser.parseAADLToAgentArrayList(modelFile);
			int taskIndex = 1;
			for (Entry<String, Set<Agent>> entry: agents.entrySet()){
				Task task  = new Task(taskIndex++);
				task.setName(entry.getKey());
				for (Agent a: entry.getValue()){
					if(a.getType().equals(Agent.AGENT_BUS)){
						for (BusAgent busAgent: busAgents){
							if (a.getName().equals(busAgent.getName())){
								task.addAgent(busAgent);   //查找原来的busAgent
								break;
							}
						}
					}else if (a.getType().equals(Agent.AGENT_CONTROL)){
						task.addAgent(a);
					}else if (a.getType().equals(Agent.AGENT_DISPLAY)){
						task.addAgent(a);
					}
				}
				tasks.add(task);
			}
		}
		
		inputData("tasks", tasks);
		StringBuffer applicationFilePath = new StringBuffer(targetDirPath);
		applicationFilePath.append("App/").append(APPLICATION_C_FILE_NAME);
		generateCodeFile(applicationFilePath.toString(), APPLICATION_C_TEMPLATE_NAME);
		
		
		List<EntityZoneCategory> entityZoneCategorys = entityZoneCategoryService.getEntityZoneCategoryByProject(project.getId());
		inputData("entityZoneCategorys", entityZoneCategorys);
		//CDSF_Configs_Bus.c
		StringBuffer cdsfConfigsBusFilePath = new StringBuffer(targetDirPath);
		cdsfConfigsBusFilePath.append("CASFConfigs/").append(CDSF_CONFIGS_BUS_FILE_NAME);
		generateCodeFile(cdsfConfigsBusFilePath.toString(), CDSF_CONFIGS_BUS_TEMPLATE_NAME);
		
	
	}
	
	private  List<Property> getEquipmentList(DesignPatternInstanceBean dpiBean){
		List<Property> equipments = dpiBean.getPropertyByName(EQUIPMENT);
		for(Property p : equipments){
			AvionicsEquipment equipment = avionicsEquipmentService.getAvionicsEquipmentByUri(p.getValue());
			if (equipment != null){
				p.setValue(equipment.getName());
			}else {
				equipments.remove(p);
			}
		}
		return equipments;
	}
	
	private  Map<String, Property> getInstanceValue(Map<String, Property> instance, Set<String> dependFiles, Map<String ,String> methodDependFiles){
		AvionicsEquipment bus = avionicsEquipmentService.getAvionicsEquipmentByUri(instance.get(BUS_TYPE).getValue());
		logger.info("Bus name:" + bus.getName());
		instance.get(BUS_TYPE).setValue(bus.getName());
		
		for (Entry<String, Property> e: instance.entrySet()){
			logger.info("[" + e.getKey() + "]=" + e.getValue().getValue());
		}
		
		logger.info("Equipment Uri:" + instance.get(EQUIPMENT).getValue());
		AvionicsEquipment equipment = avionicsEquipmentService.getAvionicsEquipmentByUri(instance.get(EQUIPMENT).getValue());
		logger.info("Equipment name:" + equipment.getName());
		instance.get(EQUIPMENT).setValue(equipment.getName());
		
		String busZoneId = instance.get(BUS_ZONE).getValue();
		BusZone busZone = busZoneService.getBusZoneById(Long.parseLong(busZoneId));
		logger.info("BusZone name:" + busZone.getName());
		instance.get(BUS_ZONE).setValue(busZone.getName());
		
		instance.get(READ_BUS_INIT_METHOD).setValue(getMethodFullName(instance.get(READ_BUS_INIT_METHOD), dependFiles, methodDependFiles));
		instance.get(READ_BUS_PROCESSING_METHOD).setValue(getMethodFullName(instance.get(READ_BUS_PROCESSING_METHOD),dependFiles, methodDependFiles));
		instance.get(WRITE_BUS_INIT_METHOD).setValue(getMethodFullName(instance.get(WRITE_BUS_INIT_METHOD), dependFiles, methodDependFiles));
		instance.get(WRITE_BUS_PROCESSING_METHOD).setValue(getMethodFullName(instance.get(WRITE_BUS_PROCESSING_METHOD), dependFiles, methodDependFiles));
			
		return instance;
	}
	
	//获取功能函数组件的函数名
	private String getMethodFullName(Property p, Set<String> dependFiles, Map<String, String> methodComponentFiles){
		String value = p.getValue();
		if (value== null || "".equals(value) || !value.contains("=")){
			return "undefined";
		}
		String[] link = value.split("=");
		InterfaceMethod method = interfaceMethodService
			.getInterfaceMethodById(Long.parseLong(link[0]));
			
		MethodComponent methodComponent = methodComponentService
			.getMethodComponentByUri(link[1]);
		
		Map<String, String> methodFiles = null;
		try {
			methodFiles = methodComponentUtil.getMethodComponentFileList(methodComponent);
		} catch (IOException e) {
			e.printStackTrace();
		}
		methodComponentFiles.putAll(methodFiles);
		 
		if (methodComponent.getCinterface() != null){
			String headFile = methodComponent.getCinterface().getName() + ".h";
			dependFiles.add(headFile);
		}else{
			String headFile = methodComponent.getHeaderFile();
			Pattern pattern = Pattern.compile("\\w+.h");
            Matcher m = pattern.matcher(headFile); 
            while(m.find()){
            	logger.debug(m.group());
            	dependFiles.add(m.group());
            }
		}
		
		if (method == null)
			return "undefined";
		String fullName = method.getName() + "()";
			return fullName;
	}
}









